package com.quan.commons.utils;

import cn.hutool.core.collection.ConcurrentHashSet;
import cn.hutool.core.util.ReflectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer;
import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;
import com.alibaba.fastjson.util.FieldInfo;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.Serializable;
import java.util.Iterator;
import java.util.Map;

/**
 * 方法Aop日志工具类
 *
 * @author hp
 * @since 2021-04-29
 */
@Slf4j
public class LogHelper {
    // 忽略的参数类型
    private static ConcurrentHashSet ignoreType = new ConcurrentHashSet();

    static {
        ignoreType.add(HttpServletResponse.class);
        ignoreType.add(HttpServletRequest.class);
        ignoreType.add(MultipartFile.class);
    }

    public static String getMethodParam(ProceedingJoinPoint point) {
        String param = null;
        if (null != point.getArgs()) {
            Map<String, Object> paramMap = AopAndElUtils.getParametersSafe(point);
            Map<String, Object> newParamMap = Maps.newHashMap();
            boolean isJsonExcetpion;
            do {
                isJsonExcetpion = false;
                for (String paramKey : paramMap.keySet()) {
                    Object paramValue = paramMap.get(paramKey);
                    if (paramValue == null) {
                        continue;
                    }
                    Class paramClazz = paramValue.getClass();
                    if (ignoreType.contains(paramClazz)) {
                        newParamMap.remove(paramKey);
                        continue;
                    }
                    newParamMap.put(paramKey, paramValue);
                }

                try {
                    param = JSON.toJSONString(newParamMap);
                } catch (JSONException e) {
                    Iterator iterator = newParamMap.values().iterator();
                    Object paramValue = null;
                    while (iterator.hasNext()) {
                        paramValue = iterator.next();
                        if (!isFastSerializableBean(paramValue)) {
                            ignoreType.add(paramValue.getClass());
                            isJsonExcetpion = true;
                        }
                    }
                } catch (Exception e) {
                    log.warn("方法入参json序列化错误", e);
                }
            } while (isJsonExcetpion);
        }

        return param;
    }

    /**
     * 是否可以json序列化
     *
     * @param object 需序列化对象
     * @return boolean 是否允许
     */
    private static boolean isFastSerializableBean(Object object) {
        Class clazz = object.getClass();
        try {
            ObjectDeserializer objectDeserializer = ParserConfig.global.getDeserializer(clazz);
            if (objectDeserializer instanceof JavaBeanDeserializer) {
                JavaBeanDeserializer javaBeanDeserializer = (JavaBeanDeserializer) objectDeserializer;
                FieldInfo[] fieldInfoArr = javaBeanDeserializer.beanInfo.fields;
                for (FieldInfo fieldInfo : fieldInfoArr) {
                    Object value = ReflectUtil.getFieldValue(object, fieldInfo.field);
                    if (value != null && !(value instanceof Serializable)) {
                        return false;
                    }
                }
            }
        } catch (Exception e) {
            return false;
        }

        return true;
    }
}
